package com.googlecode.svnj.reports;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.WebdavRequest;
import org.apache.jackrabbit.webdav.WebdavResponse;
import org.w3c.dom.Node;

import com.googlecode.svnj.RepoContext;
import com.googlecode.svnj.XMLUtil;
import com.googlecode.svnj.callbacks.FileRevCallback;
import com.googlecode.svnj.dav.IO;
import com.googlecode.svnj.dav.SVNResource;

public class FileRevsReport extends ReportRequest {

    private long startRevision, endRevision;
    private String path;
    private boolean includeMergedRevisions = false;
    
    public long getStartRevision() {
        return startRevision;
    }

    public long getEndRevision() {
        return endRevision;
    }

    public String getPath() {
        return path;
    }

    public boolean isIncludeMergedRevisions() {
        return includeMergedRevisions;
    }

    @Override
    public String getReportType() {
        return TYPE_FILE_REVS;
    }

/*
<S:file-revs-report xmlns:S="svn:">
  <S:start-revision>0</S:start-revision>
  <S:end-revision>8</S:end-revision>
  <S:path></S:path>
</S:file-revs-report>
 */
    @Override
    protected void parse(Node root) {
        startRevision = XMLUtil.getChildLong(root, "start-revision", -1L);
        endRevision = XMLUtil.getChildLong(root, "end-revision", -1L);
        includeMergedRevisions = XMLUtil.hasChild(root, "include-merged-revisions");
        path = XMLUtil.getChildText(root, "path");
    }

    @Override
    public void report(WebdavRequest req, WebdavResponse rsp,
            DavResource resource) throws DavException, IOException,
            XMLStreamException {
        rsp.setHeader("Content-Type", "text/xml; charset=\"utf-8\"");
        OutputStream os = rsp.getOutputStream();
        XMLStreamWriter xs = XMLUtil.initWriter(os, "S:file-revs-report");
        RepoContext rc = IO.get().getRepo(req);
        FileRevCallback callback = new BlameRevCallback(xs);
        SVNResource svnResource = (SVNResource) resource;
        String blamePath = svnResource.getSpecialResource().getReposPath();
        rc.getFileRevs(blamePath, startRevision, endRevision, includeMergedRevisions, callback);
        xs.writeEndDocument();
    }
    
    private class BlameRevCallback extends StaxHelper implements FileRevCallback {

        boolean deltaElemStarted = false;
        BlameRevCallback(XMLStreamWriter xs) {
            this.stream = xs;
        }
        
        public void singleRevision(String path, long rev,
                Map<String, String> revprops, boolean resultOfMerge,
                Map<String, String> propDiffs, boolean expectDeltas) throws Exception {
            elem("S:file-rev");
            att("path", path);
            att("rev", String.valueOf(rev));
            for (String pname : revprops.keySet()) {
                elem("S:rev-prop");
                att("name", pname);
                text(revprops.get(escape(pname)), true);
                end(); // rev-prop
            }
            for (String pname : propDiffs.keySet()) {
                String pval = propDiffs.get(pname);
                if (pval != null) {
                    elem("S:set-prop"); att("name", escape(pname)); text(pval, true); end();
                } else {
                    stream.writeEmptyElement("S:remove-prop");
                    att("name", escape(pname));
                }
            }
            if (!expectDeltas) end(); // file-rev
        }
        
        
        public void appendTextDelta(String deltaStr) throws Exception {
            if (!deltaElemStarted) {
                elem("S:txdelta");
                deltaElemStarted = true;
            }
            text(deltaStr, false);
        }

        public void endTextDelta() throws Exception {
            if (deltaElemStarted) {
                deltaElemStarted = false;
                end(); // txdelta
            }
            end(); // file-rev
        }

    }

}
